package operation;

import abbot.WaitTimedOutException;
import abbot.finder.BasicFinder;
import abbot.finder.ComponentNotFoundException;
import abbot.finder.MultipleComponentsFoundException;
import abbot.finder.matchers.ClassMatcher;
import abbot.tester.ActionFailedException;
import abbot.util.Condition;
import com.supermap.desktop.WorkflowView.FormWorkflow;
import com.supermap.desktop.WorkflowView.WorkflowCanvas;
import com.supermap.desktop.WorkflowView.graphics.CoordinateTransform;
import com.supermap.desktop.WorkflowView.graphics.GraphCanvas;
import com.supermap.desktop.WorkflowView.graphics.graphs.ProcessGraph;
import com.supermap.desktop.core.Application;
import com.supermap.desktop.core.Interface.IFormWorkflow;
import com.supermap.desktop.process.core.IProcess;
import com.supermap.desktop.process.tasks.TasksManager;
import org.junit.rules.ErrorCollector;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.TimeoutException;

/**
 * Created by hanyz on 2017/10/27.
 */
public class ModelWindowOperation extends Operation {
	public GraphCanvas canvas;//画布对象

	public ModelWindowOperation() throws ComponentNotFoundException, MultipleComponentsFoundException {
		if (Application.getActiveApplication().getActiveForm() instanceof IFormWorkflow)
			container = (FormWorkflow) Application.getActiveApplication().getActiveForm();
		init();
	}

	public ModelWindowOperation(Container container) throws ComponentNotFoundException, MultipleComponentsFoundException {
		this.container = container;
		init();
	}

	public void init() throws ComponentNotFoundException, MultipleComponentsFoundException {
		if (container != null) {
			canvas = ((GraphCanvas) new BasicFinder().find(new ClassMatcher(GraphCanvas.class)));
		}
	}

	/**
	 * 将画布点转为坐标点
	 *
	 * @param canvasPoint 画布范围 -2000, -2000, 4000, 4000
	 * @return
	 */
	public Point convertCanvasPoint(Point canvasPoint) {
		Point point = new Point(0, 0);
		if (canvas != null) {
			CoordinateTransform coordinateTransform = canvas.getCoordinateTransform();
			return coordinateTransform.transform(canvasPoint);
		}
		return point;
	}

	/**
	 * 将鼠标从当前停留点拖拽到容器内Point
	 *
	 * @param desPoint 容器内目标点
	 */
	public void dragToPoint(Point desPoint) {
		if (container != null) {
			Operation.robot.drag(container, desPoint.x, desPoint.y);
		}
	}

	/**
	 * 将鼠标从当前停留点拖拽到指定的canvasPoint
	 *
	 * @param canvasPoint 画布坐标点
	 */
	public void dragToCanvasPoint(Point canvasPoint) {
		if (container != null) {
			try {
				Operation.robot.mousePress(MouseEvent.BUTTON1_MASK);
				Point point = convertCanvasPoint(canvasPoint);
				Operation.robot.drop(container, point.x, point.y);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				Operation.robot.mouseRelease(MouseEvent.BUTTON1_MASK);
			}
			robot.delay(500);
		}
	}

	/**
	 * 点击指定title的模型节点
	 *
	 * @param title
	 */
	public void clickProcessGraph(String title) {
		ProcessGraph processGraph = findProcessGraph(title);
		if (processGraph != null) {
			Point location = processGraph.getCenter();
			Point point = convertCanvasPoint(location);
			Operation.robot.click(container, point.x, point.y);
		}
	}

	/**
	 * 查找指定title的模型节点
	 *
	 * @param title
	 */
	public ProcessGraph findProcessGraph(String title) {
		if (title != null && canvas != null && canvas instanceof WorkflowCanvas) {
			Class<WorkflowCanvas> workflowCanvasClass = WorkflowCanvas.class;
			try {
				Field processMapField = workflowCanvasClass.getDeclaredField("processMap");
				processMapField.setAccessible(true);
				Map<IProcess, ProcessGraph> processMap = (Map<IProcess, ProcessGraph>) processMapField.get(canvas);
				if (processMap != null) {
					Collection<ProcessGraph> values = processMap.values();
					for (ProcessGraph value : values) {
						if (title.equals(value.getTitle())) {
							return value;
						}
					}
				}
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 窗口右键菜单操作
	 * 直接调用父类的就可以了 new Operation(modelWindowOperation.getContainer()).clickRightButtonMenuItem("参数设置");
	 */

	/**
	 * 等待所有任务执行完成
	 *
	 * @param timeout  最长等待时间 ms
	 * @return 结束后，工作流状态 WORKFLOW_STATE_COMPLETED、WORKFLOW_STATE_INTERRUPTED等
	 * @throws TimeoutException
	 */
	public int waitWorkFlowCompleted(long timeout) throws TimeoutException {
		//fixme:container为空就直接抛异常吧，后面加了错误收集机制再看怎样处理。
		final FormWorkflow workFlow = ((FormWorkflow) container);
		final Condition cond = new Condition() {
			@Override
			public boolean test() {
				//任务执行完成或者失败都不需要再等待了。
				if (workFlow.getTasksManager().getStatus() == TasksManager.WORKFLOW_STATE_COMPLETED
						|| workFlow.getTasksManager().getStatus() == TasksManager.WORKFLOW_STATE_INTERRUPTED) {
					return true;
				}
				return false;
			}
		};
		//等"执行"开始执行
		robot.delay(1000);
		try {
			abbot.tester.Robot.wait(cond, timeout);
		} catch (WaitTimedOutException wto) {
			throw new ActionFailedException("waitWorkFlowCompleted timeout!");
		}
		return workFlow.getTasksManager().getStatus();
	}

	public Vector<IProcess> getExceptionProcess(){
		FormWorkflow workflow = (FormWorkflow) this.container;
		return workflow.getTasksManager().getProcesses(TasksManager.WORKER_STATE_EXCEPTION);
	}

	public void collectExceptionProcess(ErrorCollector errorCollector){
		Vector<IProcess> exceptionProcess = getExceptionProcess();
		if(errorCollector != null && exceptionProcess != null && exceptionProcess.size() > 0){
			for (IProcess exceptionProces : exceptionProcess) {
				errorCollector.addError(new Throwable("ExceptionProcess:" + exceptionProces.getTitle()));
			}
		}
	}

}
